package org.arclib.x.sprite;

import java.io.IOException;
import java.util.ArrayList;

import org.apache.log4j.Logger;
import org.arclib.Texture;
import org.arclib.draw.Color;
import org.arclib.draw.Draw;
import org.arclib.math.Point;
import org.arclib.math.Size;
import org.arclib.sound.Sound;
import org.arclib.x.sprite.frame.BoxFrame;
import org.arclib.x.sprite.frame.COLLISION_TYPE;
import org.arclib.x.sprite.frame.Frame;
import org.arclib.x.sprite.frame.RadFrame;

/// provides animations and encapulates frame collision
public class Animation
{
	// / simply set the frame length to 0
	Animation()
	{
		frames = new ArrayList<Frame>();
	}

	// / add a frame to the animation
	Size addFrame(String img, int time, Sound snd, COLLISION_TYPE col)
			throws IOException
	{
		Frame newFrame = null;

		// extract size from frames after they load
		Size size = Size.Zero;

		if (col == COLLISION_TYPE.BOX)
		{
			newFrame = new BoxFrame(img, time, snd, size);
			size = newFrame.size;
		} else if (col == COLLISION_TYPE.CIRCLE)
		{
			newFrame = new RadFrame(img, time, snd, size);
			size = newFrame.size;
		} else
		{
			log.info("invalid collision type");
		}

		frames.add(newFrame);

		return size;
	}

	// / add a frame to the animation
	Size addFrame(Texture tex, int time, Sound snd, COLLISION_TYPE col)
	{
		// grow frame length
		Frame newFrame;

		// extract size from frames after they load
		Size size = Size.Zero;

		if (col == COLLISION_TYPE.BOX)
		{
			newFrame = new BoxFrame(tex, time, snd, size);
		} else if (col == COLLISION_TYPE.CIRCLE)
		{
			newFrame = new RadFrame(tex, time, snd, size);
		} else
		{
			log.info("invalid collision type");
		}

		return size;
	}

	// / draw frame
	void draw(double x, double y, double width, double height, Color color,
			double pivX, double pivY, double angle, double nx, double ny,
			COLLISION_TYPE col)
	{
		Draw.image(frames.get(curr).getTexture(), new Point(x, y), new Size(
				width, height), new Point(pivX, pivY), angle, color);
	}

	// / process pivots, call every frame
	void process()
	{
		// time of less than 0 will be frozen
		if (frames.get(curr).getTime() > 0)
		{
			// calculate time elapsed between calls
			prevTime = currTime;
			currTime = System.currentTimeMillis();

			// add it to the amount of time elapsed so far
			elapsed += currTime - prevTime;

			// check to see if enough time elapsed to move to next frame
			if (elapsed >= frames.get(curr).getTime())
			{
				// play snd if there is one
				if (frames.get(curr).getSound() != null)
				{
					frames.get(curr).getSound().play();
				}

				// we reached the end of the frame
				if (curr == frames.size() - 1)
				{
					// loop back to beginning if specified
					if (loop)
						curr = 0;
					// otherwise just stay here
				} else
				{
					curr++;
				}

				// reset
				elapsed = 0;
			}
		}

		frames.get(curr).process();

	}

	// / get current frame of the sprite
	Frame getCurrFrame()
	{
		return frames.get(curr);
	}

	// / get curr frame num of the sprite
	int getCurr()
	{
		return curr;
	}

	// / set looping or not
	void setLoop(boolean v)
	{
		loop = v;
	}

	// / get sound from frame num
	Sound getSound(int argNum)
	{
		assert (argNum <= frames.size());
		return frames.get(argNum).getSound();
	}

	// / set sound at frame num
	void setSound(Sound snd, int argNum)
	{
		assert (argNum <= frames.size());
		// remove old sound if its there

		frames.get(argNum).setSound(snd);
	}

	// / get time at frame num
	int getTime(int aNum)
	{
		return frames.get(aNum).getTime();
	}

	// / set time at frame num
	void setTime(int aT, int aNum)
	{
		frames.get(aNum).setTime(aT);
	}

	// / reset sprite frame and time values
	void reset()
	{
		curr = 0;
		currTime = System.currentTimeMillis();
		prevTime = currTime;
		// elapsed=0;
	}

	// / tell whether or not it is looping
	boolean isLoop()
	{
		return loop;
	}

	// animation information
	private ArrayList<Frame> frames;
	private int curr = 0;
	private long prevTime = 0, currTime = 0, elapsed = 0;
	private boolean loop = true;
	private static Logger log = Logger.getLogger(Animation.class);
}
